// 循环引用
// rust内存泄漏的典型例子: 同时用Rc<T>和RefCell<T>创建循环引用,
// 最终这些引用的计数无法被归0,因此Rc<T>拥有的值也不会被释放清理.

// 何为循环引用
use crate::List::{Cons, Nil};
use std::cell::RefCell;
use std::rc::Rc;

#[derive(Debug)]
enum List {
  Cons(i32, RefCell<Rc<List>>),
  Nil,
}
impl List{
  fn tail(&self)->Option<&RefCell<Rc<List>>> {
    match self{
      Cons(_,item)=>Some(item),
      Nil => None,
    }
  }
}

fn _learn_circular_ref(){
  let a=Rc::new(Cons(5, RefCell::new(Rc::new(Nil))));
  println!("a的初始化rc计数={}", Rc::strong_count(&a));
  println!("a指向的节点={:?}", a.tail());
  // 创建b到a的引用
  let b=Rc::new(Cons(10, RefCell::new(Rc::clone(&a))));

  println!("在b创建后,a的rc计数={}", Rc::strong_count(&a));
  println!("b的初始化rc计数={}", Rc::strong_count(&b));
  println!("b指向的节点={:?}", b.tail());

  // 利用RefCell的可变性, 创建了a到b的引用
  if let Some(link)=a.tail(){
    *link.borrow_mut()=Rc::clone(&b);
  }
  println!("在更改a后,b的rc计数={}",Rc::strong_count(&b));
  println!("在更改a后,a的rc计数={}",Rc::strong_count(&a));

  // 下面一行println!将导致循环引用
  // 我们可怜的8MB大小的main线程将被它冲垮,最终造成栈溢出
  // println!("a next itme={:?}", a.tail());
}